#include "editor/gui/roomview.hpp"
#include "guichan/allegro.hpp"

namespace nmc
{
    RoomView::RoomView(TileMap* tileMap)
        : mTileMap(tileMap),
        mTileSelected(true),
        mAreaSelected(false),
        mMouseX(0),
        mMouseY(0),
        mFrameCounter(0),
        mMode(SELECT_TILES)
    {
        addMouseListener(this);
    }

    RoomView::~RoomView()
    {

    }

    void RoomView::draw(gcn::Graphics* graphics)
    {
        gcn::AllegroGraphics* allegroGraphics = static_cast<gcn::AllegroGraphics*>(graphics);

        gcn::ClipRectangle clipArea = allegroGraphics->getCurrentClipArea();

        mTileMap->draw(allegroGraphics->getTarget(),
                       -clipArea.xOffset,
                       -clipArea.yOffset,
                       TileMap::BACKGROUND_LAYER);
        mTileMap->draw(allegroGraphics->getTarget(),
                       -clipArea.xOffset,
                       -clipArea.yOffset,
                       TileMap::FOREGROUND_LAYER);
        mTileMap->draw(allegroGraphics->getTarget(),
                       -clipArea.xOffset,
                       -clipArea.yOffset,
                       TileMap::ENTITY_LAYER);

        graphics->setColor(gcn::Color(0xff0000));
        graphics->drawRectangle(gcn::Rectangle(0,
                                               0,
                                               mTileMap->getWidth()*16,
                                               mTileMap->getHeight()*16));

        // Draw door markers.
		int i;
		for (i = 0; i < mTileMap->getWidth(); i += 20)
		{
            graphics->drawLine((i + 8) * 16, 
                                0, 
                                (i + 8) * 16, 
                                8);
            graphics->drawLine((i + 12) * 16 - 1, 
                                0, 
                                (i + 12) * 16 - 1, 
                                8);
            graphics->drawLine((i + 8) * 16, 
                                mTileMap->getHeight() * 16 - 9, 
                                (i + 8) * 16, 
                                mTileMap->getHeight() * 16 - 1);
	        graphics->drawLine((i + 12) * 16 - 1,
                                mTileMap->getHeight() * 16 - 9, 
                                (i + 12) * 16 - 1, 
                                mTileMap->getHeight() * 16 - 1);
		}

		for (i = 0; i < mTileMap->getHeight(); i += 15)
		{
			graphics->drawLine(0, 
                               (i + 6) * 16, 
                               8, 
                               (i + 6) * 16);
			graphics->drawLine(0, 
                               (i + 9) * 16 - 1, 
                               8, 
                               (i + 9) * 16 - 1);
			graphics->drawLine(mTileMap->getWidth() * 16 - 9, 
                               (i + 6) * 16, 
                               mTileMap->getWidth() * 16 - 1, 
                               (i + 6) * 16);
			graphics->drawLine(mTileMap->getWidth() * 16 - 9, 
                               (i + 9) * 16 - 1, 
                               mTileMap->getWidth() * 16 - 1, 
                               (i + 9) * 16 - 1);			
		}

        if (mTileSelected && (mMode == SELECT_TILE || mMode == SELECT_TILES))
        {
            graphics->pushClipArea(gcn::Rectangle(mMouseX - mMouseX % 16,
                                                  mMouseY - mMouseY % 16,
                                                  16,
                                                  16));
            drawTileHoverMarker(graphics);
            graphics->popClipArea();
        }

        if (mAreaSelected)
        {
            drawSelectedAreaMarker(graphics);
        }
    }

    void RoomView::drawTileHoverMarker(gcn::Graphics* graphics)
    {   
        int pixelsDrawn;
        
        if (mFrameCounter % 40 < 10)
        {
            pixelsDrawn = 0;   
        }
        else if (mFrameCounter % 40 < 20)
        {
            pixelsDrawn = 1;
        }
        else if (mFrameCounter % 40 < 30)
        {
            pixelsDrawn = 2;
        }
        else
        {
            pixelsDrawn = 3;
        }

        int x;
        for (x = 0; x < 16; x++)
        {
            if (pixelsDrawn % 4 < 2)
            {
                graphics->setColor(gcn::Color(0x000000));
            }
            else
            {
                graphics->setColor(gcn::Color(0xff0000));
            }

            graphics->drawPoint(x, 0);
            graphics->drawPoint(x, 15);
            pixelsDrawn++;
        }

        int y;
        for (y = 0; y < 16; y++)
        {
            if (pixelsDrawn % 4 < 2)
            {
                graphics->setColor(gcn::Color(0x000000));
            }
            else
            {
                graphics->setColor(gcn::Color(0xff0000));
            }

            graphics->drawPoint(0, y);
            graphics->drawPoint(15, y);
            pixelsDrawn++;
        }
    }

    void RoomView::drawSelectedAreaMarker(gcn::Graphics* graphics)
    {   
        int pixelsDrawn;
        
        if (mFrameCounter % 40 < 10)
        {
            pixelsDrawn = 0;   
        }
        else if (mFrameCounter % 40 < 20)
        {
            pixelsDrawn = 1;
        }
        else if (mFrameCounter % 40 < 30)
        {
            pixelsDrawn = 2;
        }
        else
        {
            pixelsDrawn = 3;
        }

        int x;
        for (x = mSelectedArea.x; x < mSelectedArea.x + mSelectedArea.width; x++)
        {
            if (pixelsDrawn % 4 < 2)
            {
                graphics->setColor(gcn::Color(0x000000));
            }
            else
            {
                graphics->setColor(gcn::Color(0xffffff));
            }

            graphics->drawPoint(x, mSelectedArea.y);
            graphics->drawPoint(x, mSelectedArea.y + mSelectedArea.height);
            pixelsDrawn++;
        }

        int y;
        for (y = mSelectedArea.y; y < mSelectedArea.y + mSelectedArea.height; y++)
        {
            if (pixelsDrawn % 4 < 2)
            {
                graphics->setColor(gcn::Color(0x000000));
            }
            else
            {
                graphics->setColor(gcn::Color(0xffffff));
            }

            graphics->drawPoint(mSelectedArea.x, y);
            graphics->drawPoint(mSelectedArea.x + mSelectedArea.width, y);
            pixelsDrawn++;
        }
    }

    void RoomView::logic()
    {
        mFrameCounter++;
        setSize(mTileMap->getWidth()*16, 
                mTileMap->getHeight()*16);
    }

    void RoomView::mouseMoved(gcn::MouseEvent& mouseEvent)
    {
        mMouseX = mouseEvent.getX();
        mMouseY = mouseEvent.getY();
    }

    void RoomView::mouseDragged(gcn::MouseEvent& mouseEvent)
    {
        mMouseX = mouseEvent.getX();
        mMouseY = mouseEvent.getY();

        if (mMode == SELECT_TILES)
        {
            std::pair<int, int> coordinate;
            coordinate.first = (mouseEvent.getX() - mouseEvent.getX() % 16) / 16;
            coordinate.second = (mouseEvent.getY() - mouseEvent.getY() % 16) / 16;
            mSelectedTiles.insert(coordinate);  
        }
        else if (mMode == SELECT_AREA)
        {
            mAreaSelected = true;

            if (mMousePressX > mouseEvent.getX())
            {
                mSelectedArea.x = mouseEvent.getX() - mouseEvent.getX() % 16;
                mSelectedArea.width = (mMousePressX - mMousePressX % 16) - mSelectedArea.x;
            }
            else
            {
                mSelectedArea.x = mMousePressX - mMousePressX % 16;
                mSelectedArea.width = (mouseEvent.getX() - mMousePressX) 
                                        - (mouseEvent.getX() - mMousePressX + 16) % 16 + 15;
            }

            if (mSelectedArea.width < 16)
            {
               mSelectedArea.width = 16;
            }

            if (mMousePressY > mouseEvent.getY())
            {
                mSelectedArea.y = mouseEvent.getY() - mouseEvent.getY() % 16;
                mSelectedArea.height = (mMousePressY - mMousePressY % 16) - mSelectedArea.y;
            }
            else
            {
                mSelectedArea.y = mMousePressY - mMousePressY % 16;
                mSelectedArea.height = (mouseEvent.getY() - mMousePressY) 
                                        - (mouseEvent.getY() - mMousePressY + 16) % 16 + 15;
            }

            if (mSelectedArea.height < 16)
            {
                mSelectedArea.height = 16;
            }

            if (mSelectedArea.x < 0)
            {
                mSelectedArea.x = 0;
            }

            if (mSelectedArea.y < 0)
            {
                mSelectedArea.y = 0;
            }

            if (mSelectedArea.width > (mTileMap->getWidth() * 16 - mSelectedArea.x))
            {
                mSelectedArea.width = mTileMap->getWidth() * 16 - mSelectedArea.x - 1;
            }

            if (mSelectedArea.height > (mTileMap->getHeight() * 16 - mSelectedArea.y))
            {
                mSelectedArea.height = mTileMap->getHeight() * 16 - mSelectedArea.y - 1;
            }
        }
    }

    void RoomView::mousePressed(gcn::MouseEvent& mouseEvent)
    {
        mMousePressX = mouseEvent.getX();
        mMousePressY = mouseEvent.getY();

        if (mMode == SELECT_TILES)
        {
            std::pair<int, int> coordinate;
            coordinate.first = (mouseEvent.getX() - mouseEvent.getX() % 16) / 16;
            coordinate.second = (mouseEvent.getY() - mouseEvent.getY() % 16) / 16;
            mSelectedTiles.insert(coordinate);  
        }
        else if (mAreaSelected && mMode == SELECT_AREA)
        {
            mAreaSelected = false;
        }
    }

    void RoomView::mouseReleased(gcn::MouseEvent& mouseEvent)
    {
        if (isAreaSelected()
            && !mSelectedArea.isPointInRect(mMousePressX,
                                            mMousePressY))
        {
            return;
        }
           
        generateAction();

        mSelectedTiles.clear();
    }

    void RoomView::mouseEntered(gcn::MouseEvent& mouseEvent)
    {
        mTileSelected = true;
    }

    void RoomView::mouseExited(gcn::MouseEvent& mouseEvent)
    {
        mTileSelected = false;
    }

    void RoomView::setMode(RoomViewMode mode)
    {
        mMode = mode;
    }

    unsigned int RoomView::getMode()
    {
        return mMode;
    }

    gcn::Rectangle RoomView::getSelectedTile()
    {
        return gcn::Rectangle((mMouseX - mMouseX % 16) / 16,
                              (mMouseY - mMouseY % 16) / 16,
                              1,
                              1);
    }

    std::set<std::pair<int, int> > RoomView::getSelectedTiles()
    {
        return mSelectedTiles;
    }

    gcn::Rectangle RoomView::getSelectedArea()
    {
        return gcn::Rectangle(mSelectedArea.x / 16,
                              mSelectedArea.y / 16,
                              mSelectedArea.width / 16 + 1,
                              mSelectedArea.height / 16 + 1);
    }

    bool RoomView::isAreaSelected()
    {
        return mAreaSelected;
    }

    void RoomView::selectAll()
    {
        mSelectedArea.x = 0;
        mSelectedArea.y = 0;
        mSelectedArea.width = mTileMap->getWidth() * 16 - 1;
        mSelectedArea.height = mTileMap->getHeight() * 16 - 1;
        mAreaSelected = true;
    }

    void RoomView::selectNone()
    {
        mAreaSelected = false;
    }
}